Кращі практики MVC
==================
Недивлячись на те, що MVC відомий практично кожному веб-розробнику, його
використання у реальних проектах часто викликає труднощі. Головна ідея
MVC — **повторне використання коду та розділення проблем**. У даному розділі
будуть описані загальні принципи, які допоможуть слідувати MVC у вашому додатку.

Допустимо, що веб-додаток складається із декількох піддодатків, таких як

* front end: та частина сайту, яку бачать користувачі;
* back end: адміністративна частина сайту, яка дозволяє керувати додатком.
Доступ до неї зазвичай обмежений;
* консоль: додаток, який складається із набору консольних команд та запускається у вікні терміналу або як завдання cron-у;
* API: надає стороннім додаткам інтерфейси для інтеграції з вашим додатком.

Піддодатки можуть бути реалізовані у вигляді [модулів](/doc/guide/basics.module)
або як додаток, який містить код, загальний для декількох піддодатків.


Модель
------
[Моделі](/doc/guide/basics.model) представляють структури даних, які
використовуться у додатку, і часто є спільними для кількох піддодатків.
Наприклад, модель `LoginForm` може бути використана як у користувальницькій, так
і у адміністративній частині додатку. Модель `News` може використовуватися
консольними командами, API та front/back частинами додатку. Тому, моделі

* повинні містити властивості, які представляють конкретні дані;

* повинні включати у себе бізнес-логіку (наприклад, правила валідації) для
того, щоб переконатися, що дані відповідають вимогам;

* можуть містити код для роботи із даними. Наприклад, модель `SearchForm`,
окрім даних  для пошуку, може містити метод `search`, який цей пошук здійснює.

Іноді слідування останньому перерахованому правилу робить модель дуже
товстою, тобто вона містить дуже багато коду в одному класі. Це може призвести
до труднощів підтримки коду у тому випадку, якщо модель використовується декількома
способами. Приміром, модель `News` може містити метод `getLatestNews`,
який використовується тільки користувальницькою частиною і метод `getDeletedNews`,
який використовується тільки адміністративною частиною. Для невеликих та середніх
додатків це припустимо. Для великих додатків з метою поліпшення
підтримуваності коду можна зробити наступне:

* Створити модель `NewsBase`, яка містить тільки код, загальний для піддодатків
(користувальницької та административної частин);

* У кожному піддодатку створити модель `News`, наслідувану від `NewsBase` та
визначити у ній специфічні для піддодатку методи.

Таким чином, якщо застосувати це до розглянутому вище прикладу, необхідно
додати модель `News` із методом `getLatestNews` у користувальницьку частину та
ще одну модель `News` із методом `getDeletedNews` у адміністративну частину.

У загальному випадку моделі не повинні безпосередньо взаємодіяти з користувачем. тобто:

* не повинні використовувати `$_GET`, `$_POST` або інші подібні змінні, які напряму
 отримуємо із запиту користувача, так як моделі можуть використовуватися у
 зовсім інших піддодатках (наприклад, у модульних тестах або API), у
 яких ці змінні недоступні. Всі змінні, які відносяться до запиту 
 користувача, повинні оброблятися у контролері;

* не повинні генерувати HTML або інший код представлення, так як він
 може змінюватися незалежно від потреб користувача (тобто, користувальницька частина
 та адміністративна частина можуть відображати новини у абсолютно різному форматі).
 Такий код повинен оброблятися у представленнях.


Представлення
-------------

[Представлення](/doc/guide/basics.view) відповідають за відображення моделей у
потрібному користувачу форматі. У загальному випадку представлення

* повинні, головним чином, містити розмітку, таку як HTML, або простий PHP код,
який використовується для обходу, форматування та відображення даних;

* не повинні безпосередньо звертатися до бази даних. Цим повинні займатися моделі;

* не повинні безпосередньо звертатися до `$_GET`, `$_POST` та іншим змінним, які отримуються
із запиту користувача. Цю задачу повинен виконувати контролер. Представлення повинно
використовуватися для задання зовнішнього вигляду даних, отриманих із контролера та моделі;

* може безпосередньо звертатися до властивостей та методів контролера або моделей.
При цьому дані властивості та методи повинні відповідати за відображення.


Представлення можна використовувати повторно кількома способами:

* Загальний шаблон: у нього можна винести розмітку, загальну для всіх сторінок.
Наприклад, шапку та підвал;

* Частини шаблону: використовуються всередині інших шаблонів та, як правило, не
використовуються із загальним шаблоном. Приміром, частину шаблону `_form.php` можна
використовувати для відображення форми вводу моделі, яка буде використовуватися
як при її створенні, так і при редагуванні;

* Віджети: використовуються у тому випадку, коли для частини шаблону  потрібно занадто
 багато логіки. При цьому логіка переноситься у клас віджета. Віджет, який генерує
 велику кількість розмітки, може використовувати свої шаблони представлень;

* Хелпери: у шаблонах часто потрібно виконувати невеликі завдання, такі як
 форматування даних або генерація HTML-тегів. Замість того, щоб вставляти
 код безпосередньоу у шаблони, можна помістити його в клас-хелпер та використовувати цей клас 
 у шаблонах. Наприклад, такий підхід можна знайти у класі [CHtml], який допомогає генерувати
 часто використовуваний HTML код. Для того, щоб уникнути  явного підключення класів,
 хелпери можна помістити у [окрему директорію, яка прописана у import](/doc/guide/basics.namespace).


Контролер
---------

[Контролери](/doc/guide/basics.controller) — сполучна ланка, яка поєднує
моделі, представлення та інші компоненти у робочий додаток. Контролер відповідає
за обробку запитів користувача. Тому контролер

* може звертатися до `$_GET`, `$_POST` та інших змінних PHP, які отримуються із
 запиту користувача;

* може створювати екземпляри моделей та керувати ними. Приміром, у типової дії
оновлення моделі контролер може спочатку створити екземпляр моделі, потім
заповнити його даними із `$_POST` та, після вдалого збереження моделі, перенаправити
браузер користувача на сторінку створеної моделі. Слід відмітити, що саме зберігання
моделі повинно бути реалізоване у моделі, а не в контролері;

* не повинен містити SQL-запитів. Їх краще тримати у моделях;

* не повинен містити HTML та іншої розмітки. Її варто винести у представлення.


У добре спроектованому MVC-додатку контролери зазвичай дуже тонкі та
містять тільки декілька десятків рядків коду. У той же час, моделі дуже товсті
та містять більшу частину коду, повʼязану із обробкою даних, так як структура
даних та бізнес-логіка, які там міститься, зазвичай доволі специфічні для конкретного
додатку. Логіка контролеру, навпаки, доволі типова та може бути винесена у базові класи.